// services/redis_session_service.go
package services

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"strconv"
	"time"

	"bsm/daos"
	"bsm/logger"
	"bsm/models"
	"bsm/utils"

	"github.com/redis/go-redis/v9"
)

type RedisSessionService interface {
	CreateSession(user models.WebUser, token, userAgent, ip string) (*models.Session, error)
	RemoveSession(sessionID string) error
	RemoveSessionByToken(token string) error
	GetUserSessions(userID string) ([]models.Session, error)
	GetActiveSessionsCount(userID string) (int, error)
	UpdateSessionActivity(sessionID string) error
	GetSession(sessionID string) (*models.Session, error)
	GetSessionByToken(token string) (*models.Session, error)
	TerminateOtherSessions(userID int, currentSessionID string) (int, error)
	StartAutoCleanup(interval time.Duration)
	CleanupExpiredSessions() error

	GetAllActiveSessions() ([]models.Session, error)
	GetAllActiveSessionsCount() (int, error)
	GetActiveSessionsByTimeRange(startTime, endTime time.Time) ([]models.Session, error)
}

type redisSessionServiceImpl struct {
	client        *redis.Client
	ctx           context.Context
	isRedisActive bool
}

func NewRedisSessionService() RedisSessionService {
	client := daos.SafeGetRedisClient() // 使用安全获取方法

	if client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "NewRedisSessionService",
		}).Warnf("Redis不可用 - 运行在降级模式")
		return &redisSessionServiceImpl{
			client:        nil,
			ctx:           context.Background(),
			isRedisActive: false,
		}
	}

	logger.WithFields(map[string]interface{}{
		"layer":     "service",
		"operation": "NewRedisSessionService",
	}).Infof("Redis会话服务初始化成功")
	return &redisSessionServiceImpl{
		client:        client,
		ctx:           context.Background(),
		isRedisActive: true,
	}
}

func (s *redisSessionServiceImpl) CreateSession(user models.WebUser, token, userAgent, ip string) (*models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "CreateSession",
		}).Errorf("CreateSession: redis client not available")
		return nil, fmt.Errorf("CreateSession: redis client not available")
	}

	sessionID := utils.GenerateSessionID()
	now := time.Now()

	session := &models.Session{
		SessionID:  sessionID,
		UserID:     user.UserID,
		LoginTime:  now,
		LastActive: now,
		UserAgent:  userAgent,
		IPAddress:  ip,
		Token:      token,
	}

	// 序列化会话数据
	sessionData, err := json.Marshal(session)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "CreateSession",
		}).Errorf("CreateSession: failed to marshal session: %v", err)
		return nil, fmt.Errorf("failed to marshal session: %v", err)
	}

	// 使用Pipeline批量操作
	pipe := s.client.Pipeline()

	// 存储会话详情（24小时过期）
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	pipe.Set(s.ctx, sessionKey, sessionData, 24*time.Hour)

	// 添加到用户会话集合
	userSessionsKey := fmt.Sprintf("user_sessions:%s", user.UserID)
	pipe.SAdd(s.ctx, userSessionsKey, sessionID)
	pipe.Expire(s.ctx, userSessionsKey, 24*time.Hour)

	// 添加到会话最后活跃时间排序集合
	pipe.ZAdd(s.ctx, "sessions:last_active", redis.Z{
		Score:  float64(now.Unix()),
		Member: sessionID,
	})

	// 新增：建立 token 到 sessionID 的映射
	tokenKey := fmt.Sprintf("token:%s", token)
	pipe.Set(s.ctx, tokenKey, sessionID, 24*time.Hour)

	// 执行所有操作
	_, err = pipe.Exec(s.ctx)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "CreateSession",
		}).Errorf("CreateSession: failed to execute redis operations: %v", err)
		return nil, fmt.Errorf("failed to execute redis operations: %v", err)
	}

	return session, nil
}

func (s *redisSessionServiceImpl) RemoveSession(sessionID string) error {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "RemoveSession",
		}).Errorf("RemoveSession: redis client not available")
		return fmt.Errorf("RemoveSession: redis client not available")
	}

	// 先获取会话信息以得到UserID
	session, err := s.GetSession(sessionID)
	if err != nil {
		return err
	}

	pipe := s.client.Pipeline()

	// 删除会话数据
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	pipe.Del(s.ctx, sessionKey)

	// 从用户会话集合中移除
	userSessionsKey := fmt.Sprintf("user_sessions:%s", session.UserID)
	pipe.SRem(s.ctx, userSessionsKey, sessionID)

	// 从最后活跃索引中移除
	pipe.ZRem(s.ctx, "sessions:last_active", sessionID)

	// 新增：删除 token 映射
	tokenKey := fmt.Sprintf("token:%s", session.Token)
	pipe.Del(s.ctx, tokenKey)

	_, err = pipe.Exec(s.ctx)
	return err
}

func (s *redisSessionServiceImpl) RemoveSessionByToken(token string) error {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "RemoveSessionByToken",
		}).Errorf("RemoveSessionByToken: redis client not available")
		return fmt.Errorf("RemoveSessionByToken: redis client not available")
	}

	// 通过扫描所有会话来查找匹配的token
	// 使用ZSCAN遍历sessions:last_active集合来找到所有会话ID
	var matchingSessionID string
	var cursor uint64 = 0
	const count int64 = 100

	for {
		var keys []string
		var err error
		keys, cursor, err = s.client.ZScan(s.ctx, "sessions:last_active", cursor, "*", count).Result()
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":     "service",
				"operation": "RemoveSessionByToken",
			}).Errorf("RemoveSessionByToken: failed to scan sessions: %v", err)
			return fmt.Errorf("failed to scan sessions: %v", err)
		}

		// 检查每个会话的token
		for i := 0; i < len(keys); i += 2 {
			sessionID := keys[i]
			session, err := s.GetSession(sessionID)
			if err == nil && session != nil && session.Token == token {
				matchingSessionID = sessionID
				break
			}
		}

		if matchingSessionID != "" || cursor == 0 {
			break
		}
	}

	if matchingSessionID == "" {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "RemoveSessionByToken",
		}).Errorf("RemoveSessionByToken: session with token not found: %s", token)
		return fmt.Errorf("session with token not found: %s", token)
	}

	// 找到匹配的sessionID后，调用现有的RemoveSession方法
	return s.RemoveSession(matchingSessionID)
}

func (s *redisSessionServiceImpl) GetUserSessions(userID string) ([]models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetUserSessions",
		}).Errorf("GetUserSessions: redis client not available")
		return nil, fmt.Errorf("GetUserSessions: redis client not available")
	}

	userSessionsKey := fmt.Sprintf("user_sessions:%s", userID)
	sessionIDs, err := s.client.SMembers(s.ctx, userSessionsKey).Result()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetUserSessions",
		}).Errorf("GetUserSessions: failed to get user sessions: %v", err)
		return nil, err
	}

	var sessions []models.Session
	for _, sessionID := range sessionIDs {
		session, err := s.GetSession(sessionID)
		if err == nil && session != nil {
			sessions = append(sessions, *session)
		}
	}

	return sessions, nil
}

func (s *redisSessionServiceImpl) GetSession(sessionID string) (*models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSession",
		}).Errorf("GetSession: redis client not available")
		return nil, fmt.Errorf("GetSession: redis client not available")
	}

	sessionKey := fmt.Sprintf("session:%s", sessionID)
	sessionData, err := s.client.Get(s.ctx, sessionKey).Bytes()
	if err != nil {
		return nil, err
	}

	var session models.Session
	err = json.Unmarshal(sessionData, &session)
	if session.IPAddress == "::1" {
		session.IPAddress = "本机"
	}
	if err != nil {
		return nil, err
	}

	return &session, nil
}

// GetSessionByToken 根据token获取会话
func (s *redisSessionServiceImpl) GetSessionByToken(token string) (*models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSessionByToken",
		}).Errorf("GetSessionByToken: redis client not available")
		return nil, fmt.Errorf("GetSessionByToken: redis client not available")
	}

	// 通过token直接查找sessionID
	tokenKey := fmt.Sprintf("token:%s", token)
	sessionID, err := s.client.Get(s.ctx, tokenKey).Result()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSessionByToken",
		}).Errorf("GetSessionByToken: session not found for token: %v", err) // token 不存在或已过期
		return nil, fmt.Errorf("session not found for token: %v", err)
	}

	// 根据sessionID获取会话详情
	return s.GetSession(sessionID)
}

func (s *redisSessionServiceImpl) checkConnection() error {
	// 添加空指针检查
	if s == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSessionByToken",
		}).Errorf("GetSessionByToken: RedisSessionService is nil")
		return fmt.Errorf("checkConnection: RedisSessionService is nil")
	}

	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSessionByToken",
		}).Errorf("GetSessionByToken: redis client is not initialized")
		return fmt.Errorf("checkConnection: redis client is not initialized")
	}

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	_, err := s.client.Ping(ctx).Result()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetSessionByToken",
		}).Errorf("GetSessionByToken: redis连接已关闭: %v", err)
		return fmt.Errorf("redis连接已关闭: %v", err)
	}
	return nil
}

func (s *redisSessionServiceImpl) GetActiveSessionsCount(userID string) (int, error) {
	// 检查连接状态
	if err := s.checkConnection(); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetActiveSessionsCount",
		}).Warnf("GetActiveSessionsCount: redis connection check failed: %v", err)
		// 降级处理：返回0表示没有活跃会话
		return 0, nil
	}

	userSessionsKey := fmt.Sprintf("user_sessions:%s", userID)
	count, err := s.client.SCard(s.ctx, userSessionsKey).Result()
	if err != nil {
		return 0, err
	}
	return int(count), nil
}

func (s *redisSessionServiceImpl) UpdateSessionActivity(sessionID string) error {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "UpdateSessionActivity",
		}).Errorf("UpdateSessionActivity: redis client not available")
		return fmt.Errorf("UpdateSessionActivity: redis client not available")
	}

	now := time.Now()

	// 先获取会话
	session, err := s.GetSession(sessionID)
	if err != nil {
		return err
	}

	// 更新最后活跃时间
	session.LastActive = now
	sessionData, err := json.Marshal(session)
	if err != nil {
		return err
	}

	pipe := s.client.Pipeline()

	// 更新会话数据并重置过期时间
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	pipe.Set(s.ctx, sessionKey, sessionData, 24*time.Hour)

	// 更新最后活跃索引
	pipe.ZAdd(s.ctx, "sessions:last_active", redis.Z{
		Score:  float64(now.Unix()),
		Member: sessionID,
	})

	_, err = pipe.Exec(s.ctx)
	return err
}

func (s *redisSessionServiceImpl) TerminateOtherSessions(userID int, currentSessionID string) (int, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "TerminateOtherSessions",
		}).Errorf("TerminateOtherSessions: redis client not available")
		return 0, fmt.Errorf("TerminateOtherSessions: redis client not available")
	}

	userSessionsKey := fmt.Sprintf("user_sessions:%d", userID)

	// 获取所有会话ID
	sessionIDs, err := s.client.SMembers(s.ctx, userSessionsKey).Result()
	if err != nil {
		return 0, err
	}

	terminated := 0
	pipe := s.client.Pipeline()

	for _, sessionID := range sessionIDs {
		if sessionID != currentSessionID {
			// 删除会话数据
			sessionKey := fmt.Sprintf("session:%s", sessionID)
			pipe.Del(s.ctx, sessionKey)

			// 从用户集合中移除
			pipe.SRem(s.ctx, userSessionsKey, sessionID)

			// 从索引中移除
			pipe.ZRem(s.ctx, "sessions:last_active", sessionID)

			terminated++
		}
	}

	_, err = pipe.Exec(s.ctx)
	if err != nil {
		return 0, err
	}

	return terminated, nil
}

func (s *redisSessionServiceImpl) StartAutoCleanup(interval time.Duration) {
	go func() {
		ticker := time.NewTicker(interval)
		defer ticker.Stop()

		for range ticker.C {
			if err := s.CleanupExpiredSessions(); err != nil {
				log.Printf("自动清理会话失败: %v", err)
			} else {
				log.Println("自动清理会话完成")
			}
		}
	}()
}

// 增强的清理方法
func (s *redisSessionServiceImpl) CleanupExpiredSessions() error {
	if s.client == nil {
		return nil
	}

	// 清理24小时未活跃的会话索引
	cutoff := time.Now().Add(-24 * time.Hour).Unix()
	expiredSessions, err := s.client.ZRangeByScore(s.ctx, "sessions:last_active", &redis.ZRangeBy{
		Min: "0",
		Max: strconv.FormatInt(cutoff, 10),
	}).Result()

	if err != nil {
		return err
	}

	// 删除过期的会话数据
	for _, sessionID := range expiredSessions {
		// 获取会话信息以得到UserID
		session, err := s.GetSession(sessionID)
		if err == nil && session != nil {
			// 从用户会话集合中移除
			userSessionsKey := fmt.Sprintf("user_sessions:%s", session.UserID)
			s.client.SRem(s.ctx, userSessionsKey, sessionID)
		}

		// 删除会话数据
		sessionKey := fmt.Sprintf("session:%s", sessionID)
		s.client.Del(s.ctx, sessionKey)

		// 从索引中移除
		s.client.ZRem(s.ctx, "sessions:last_active", sessionID)
	}

	return nil
}

// GetAllActiveSessions 获取所有活跃会话
func (s *redisSessionServiceImpl) GetAllActiveSessions() ([]models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetAllActiveSessions",
		}).Errorf("GetAllActiveSessions: redis client not available")
		return nil, fmt.Errorf("GetAllActiveSessions: redis client not available")
	}

	// 获取所有会话ID（从最后活跃时间排序集合中）
	sessionIDs, err := s.client.ZRange(s.ctx, "sessions:last_active", 0, -1).Result()
	if err != nil {
		return nil, fmt.Errorf("failed to get session IDs: %v", err)
	}

	var sessions []models.Session
	for _, sessionID := range sessionIDs {
		session, err := s.GetSession(sessionID)
		if err == nil && session != nil {
			sessions = append(sessions, *session)
		}
	}

	return sessions, nil
}

// GetAllActiveSessionsCount 获取所有活跃会话的数量
func (s *redisSessionServiceImpl) GetAllActiveSessionsCount() (int, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetAllActiveSessionsCount",
		}).Errorf("GetAllActiveSessionsCount: redis client not available")
		return 0, fmt.Errorf("GetAllActiveSessionsCount: redis client not available")
	}

	count, err := s.client.ZCard(s.ctx, "sessions:last_active").Result()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetAllActiveSessionsCount",
		}).Errorf("GetAllActiveSessionsCount: failed to get active sessions count: %v", err)
		return 0, fmt.Errorf("failed to get active sessions count: %v", err)
	}

	return int(count), nil
}

// GetActiveSessionsByTimeRange 根据时间范围获取活跃会话
func (s *redisSessionServiceImpl) GetActiveSessionsByTimeRange(startTime, endTime time.Time) ([]models.Session, error) {
	if s.client == nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetActiveSessionsByTimeRange",
		}).Errorf("GetActiveSessionsByTimeRange: redis client not available")
		return nil, fmt.Errorf("GetActiveSessionsByTimeRange: redis client not available")
	}

	// 根据时间范围查询会话ID
	minScore := strconv.FormatInt(startTime.Unix(), 10)
	maxScore := strconv.FormatInt(endTime.Unix(), 10)

	sessionIDs, err := s.client.ZRangeByScore(s.ctx, "sessions:last_active", &redis.ZRangeBy{
		Min: minScore,
		Max: maxScore,
	}).Result()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "GetActiveSessionsByTimeRange",
		}).Errorf("GetActiveSessionsByTimeRange: failed to get session IDs by time range: %v", err)
		return nil, fmt.Errorf("failed to get session IDs by time range: %v", err)
	}

	var sessions []models.Session
	for _, sessionID := range sessionIDs {
		session, err := s.GetSession(sessionID)
		if err == nil && session != nil {
			sessions = append(sessions, *session)
		}
	}

	return sessions, nil
}
